﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace TheGame
{
    //SligAI definisce l'automa per la gestione del comportamento 
    //di uno Slig
    //[pp.43]
    public class SligAI
    {
        #region Vars
        public Game1 game;
        public PRECONDITION precond = null;
        public bool FINISHEDExecution = false;
        public bool FINISHEDTransition = true;
        public Slig Slig;
        public STATE CURRENT_STATE;
        public STATE PREV_STATE;

        public STATE WAIT;
        public STATE SENTINELLA;
        public STATE GOBACKHOME;
        public STATE GOBACKHOME2;
        public STATE ONEPASS;
        public STATE VEDETTA;
        public STATE VEDETTA2;
        public STATE SHOOT;
        public STATE RUNNER;
        public STATE RUNSTOP;
        public STATE SLEEP;
        public STATE DEAD;
        public STATE POSSESSED;
        public STATE SUICIDE;
        public STATE SHOOTED;

        public STATE JUSTPOSSESSED;
        public STATE WAITCONTROL;
        public STATE SENTINELLACONTROL;
        public STATE RUNNERCONTROL;
        public STATE RUNSTOPCONTROL;
        public STATE SHOOTCONTROL;

        public STATE CRAZY1;
        public STATE CRAZY2;

        PRECONDITIONS PRECONDITIONS;
        ACTIONS ACTIONS;

        List<string> colTypes = new List<string>();

        public bool ABE_DETECTED = false;
        #endregion

        public SligAI(Slig Slig, Game1 game,string state)
        {
            this.game = game;
            this.Slig = Slig;

            PRECONDITIONS = new PRECONDITIONS(this); 
            ACTIONS = new ACTIONS(this);

            WAIT = new STATE("WAIT",this);
            SENTINELLA = new STATE("SENTINELLA", this);
            GOBACKHOME = new STATE("GOBACKHOME", this);
            GOBACKHOME2 = new STATE("GOBACKHOME2", this); 
            ONEPASS = new STATE("ONEPASS", this);
            VEDETTA = new STATE("VEDETTA", this);
            VEDETTA2 = new STATE("VEDETTA2", this);
            SHOOT = new STATE("SHOOT", this);
            RUNNER = new STATE("RUNNER", this);
            RUNSTOP = new STATE("RUNSTOP", this);
            SLEEP = new STATE("SLEEP", this);
            DEAD = new STATE("DEAD", this);
            POSSESSED = new STATE("POSSESSED", this);
            SUICIDE = new STATE("SUICIDE", this);
            SHOOTED = new STATE("SHOOTED", this);

            JUSTPOSSESSED =  new STATE("JUSTPOSSESSED", this);
            WAITCONTROL = new STATE("WAITCONTROL", this);
            SENTINELLACONTROL = new STATE("SENTINELLACONTROL", this);
            RUNNERCONTROL = new STATE("RUNNERCONTROL", this);
            RUNSTOPCONTROL = new STATE("RUNSTOPCONTROL", this);
            SHOOTCONTROL = new STATE("SHOOTCONTROL", this);

            CRAZY1 = new STATE("CRAZY1", this);
            CRAZY2 = new STATE("CRAZY2", this);

            //////////////SLIG  AI///////////
            SLEEP.LinkTO(SENTINELLA).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.ABENOISE,PRECONDITIONS.ABEAHEAD), ACTIONS.AND(ACTIONS.WAKE,ACTIONS.WHAAT));
            SLEEP.LinkTO(SENTINELLA).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.ABENOISE, PRECONDITIONS.ABEBEHIND), ACTIONS.AND(ACTIONS.WAKE, ACTIONS.AND(ACTIONS.WHAAT, ACTIONS.AND(ACTIONS.TURN,ACTIONS.START))));
            SLEEP.LinkTO(CRAZY1).addPRECONDITION(PRECONDITIONS.ABEOMM,ACTIONS.WAKE);
            WAIT.LinkTO(SENTINELLA).addPRECONDITION(PRECONDITIONS.ABENOISE, ACTIONS.TURN);
            WAIT.LinkTO(SENTINELLA).addPRECONDITION(PRECONDITIONS.ENDSTATE,ACTIONS.START);
            
            SENTINELLA.LinkTO(SHOOT).addPRECONDITION(PRECONDITIONS.LOOKATMUDOKON, ACTIONS.AND(ACTIONS.STOP,ACTIONS.FREEZE));
            SENTINELLA.LinkTO(SENTINELLA).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.ABENOISE, PRECONDITIONS.ABEBEHIND), ACTIONS.AND(ACTIONS.AND(ACTIONS.STOP, ACTIONS.AND(ACTIONS.WHAAT, ACTIONS.TURN)), ACTIONS.START));
            SENTINELLA.LinkTO(SENTINELLA).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.ABENOISE, PRECONDITIONS.ABEAHEAD), ACTIONS.AND(ACTIONS.AND(ACTIONS.STOP,ACTIONS.WHAAT), ACTIONS.AND(ACTIONS.WAIT,ACTIONS.START)));
            SENTINELLA.LinkTO(SENTINELLA).addPRECONDITION(PRECONDITIONS.BLOCK, ACTIONS.AND(ACTIONS.AND(ACTIONS.STOP, ACTIONS.WAIT.REPEAT(1)), ACTIONS.TURN));
            SENTINELLA.LinkTO(DEAD).addPRECONDITION(PRECONDITIONS.GODOWND, ACTIONS.DOWNPLANE);
            SENTINELLA.LinkTO(SENTINELLA).addPRECONDITION(PRECONDITIONS.ENDSCREEN, ACTIONS.AND(ACTIONS.AND(ACTIONS.STOP, ACTIONS.WAIT.REPEAT(1)), ACTIONS.TURN));
            SENTINELLA.LinkTO(DEAD).addPRECONDITION(PRECONDITIONS.MATTATOIO, ACTIONS.SPLAT);
            SENTINELLA.LinkTO(CRAZY1).addPRECONDITION(PRECONDITIONS.ABEOMM);

            //SHOOT.LinkTO(RUNNER).addPRECONDITION(PRECONDITIONS.ENDSTATE, ACTIONS.AND(ACTIONS.SHOOTSTOP, ACTIONS.RUNSTART));
            SHOOT.LinkTO(RUNNER).addPRECONDITION(PRECONDITIONS.NOTLOOKATABE, ACTIONS.AND(ACTIONS.SHOOTSTOP,ACTIONS.RUNSTART));//Aggiungere SligWhAaaat
            SHOOT.LinkTO(RUNNER).addPRECONDITION(PRECONDITIONS.ABENOTSAMELVL, ACTIONS.AND(ACTIONS.SHOOTSTOP, ACTIONS.RUNSTART));//Aggiungere SligWhAaaat
            SHOOT.LinkTO(SENTINELLA).addPRECONDITION(PRECONDITIONS.ABEKILLED, ACTIONS.START);
            //SHOOT.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.ENDSTATE);
            //SHOOT.LinkTO(SHOOT).addPRECONDITION(PRECONDITIONS.ENDSTATE, ACTIONS.AND(ACTIONS.SHOOTSTOP, ACTIONS.SHOOTSTART));

            RUNNER.LinkTO(SENTINELLA).addPRECONDITION(PRECONDITIONS.BLOCK, ACTIONS.OUCH);
            RUNNER.LinkTO(RUNNER).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.ABENOTSAMELVL,PRECONDITIONS.ABEBEHIND),ACTIONS.AND(ACTIONS.AND(ACTIONS.RUNSTOP,ACTIONS.TURN),ACTIONS.RUNSTART));
            RUNNER.LinkTO(RUNSTOP).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.ENDSTATE, PRECONDITIONS.ABESAMELVL));
            
            //RUNNER.LinkTO(RUNSTOP).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.LVLCHANGED,PRECONDITIONS.AND(PRECONDITIONS.ENDSTATE, PRECONDITIONS.ABESAMELVL)));
            //RUNNER.LinkTO(RUNSTOP).addPRECONDITION(PRECONDITIONS.LOOKATMUDOKON);
            //RUNNER.LinkTO(RUNSTOP).addPRECONDITION(PRECONDITIONS.BLOCK);
            //RUNNER.LinkTO(RUNSTOP).addPRECONDITION(PRECONDITIONS.ENDSCREEN);
            //RUNNER.LinkTO(RUNNER).addPRECONDITION(PRECONDITIONS.GODOWN, ACTIONS.AND(ACTIONS.RUNSTOP, ACTIONS.AND(ACTIONS.TURN, ACTIONS.RUNSTART)));
            RUNSTOP.LinkTO(SENTINELLA).addPRECONDITION(PRECONDITIONS.BLOCK, ACTIONS.OUCH);
            RUNSTOP.LinkTO(VEDETTA2).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.ENDSTATE,PRECONDITIONS.NOTATHOME));
            RUNSTOP.LinkTO(VEDETTA).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.ENDSTATE, PRECONDITIONS.ATHOME));

            VEDETTA2.LinkTO(GOBACKHOME).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.ENDSTATE,PRECONDITIONS.ABESAMELVL), ACTIONS.TURN);
            VEDETTA2.LinkTO(GOBACKHOME2).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.ENDSTATE, PRECONDITIONS.ABENOTSAMELVL));
            VEDETTA2.LinkTO(SHOOT).addPRECONDITION(PRECONDITIONS.LOOKATMUDOKON, ACTIONS.SHOOTSTART);
            
            VEDETTA.LinkTO(SHOOT).addPRECONDITION(PRECONDITIONS.LOOKATMUDOKON, ACTIONS.SHOOTSTART);
            VEDETTA.LinkTO(SENTINELLA).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.AND(PRECONDITIONS.ATHOME, PRECONDITIONS.ENDSTATE), PRECONDITIONS.NOTLOOKATABE), ACTIONS.START);
            VEDETTA.LinkTO(GOBACKHOME).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.NOTATHOME,PRECONDITIONS.ENDSTATE), ACTIONS.TURN);
            VEDETTA.LinkTO(SENTINELLA).addPRECONDITION(PRECONDITIONS.ABENOTSAMELVL);

            CRAZY2.LinkTO(VEDETTA).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.ENDSTATE, PRECONDITIONS.ABENOTOMM));
            CRAZY1.LinkTO(SHOOT).addPRECONDITION(PRECONDITIONS.LOOKATMUDOKON, ACTIONS.AND(ACTIONS.STOP, ACTIONS.FREEZE));
            CRAZY1.LinkTO(CRAZY1).addPRECONDITION(PRECONDITIONS.BLOCK,ACTIONS.AND(ACTIONS.OUCH,ACTIONS.AND(ACTIONS.TURN,ACTIONS.RUNSTART)));
            CRAZY1.LinkTO(CRAZY2).addPRECONDITION(PRECONDITIONS.ENDSCREEN);
            CRAZY1.LinkTO(CRAZY2).addPRECONDITION(PRECONDITIONS.ENDSTATE);
            CRAZY2.LinkTO(POSSESSED).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.ENDSTATE, PRECONDITIONS.ABECONTROL));
            CRAZY2.LinkTO(CRAZY1).addPRECONDITION(PRECONDITIONS.ENDSTATE, ACTIONS.AND(ACTIONS.TURN, ACTIONS.RUNSTART));
            
            SHOOTED.LinkTO(DEAD).addPRECONDITION(PRECONDITIONS.ENDSTATE, ACTIONS.SPLAT);

            ///////////////SLIG  CONTROL////////////////
            POSSESSED.LinkTO(JUSTPOSSESSED).addPRECONDITION(PRECONDITIONS.ENDSTATE);
            JUSTPOSSESSED.LinkTO(WAITCONTROL).addPRECONDITION(PRECONDITIONS.ENDSTATE);

            WAITCONTROL.LinkTO(WAITCONTROL).addPRECONDITION(PRECONDITIONS.TURN, ACTIONS.TURN);
            WAITCONTROL.LinkTO(WAITCONTROL).addPRECONDITION(PRECONDITIONS.BLOCK);
            WAITCONTROL.LinkTO(RUNNERCONTROL).addPRECONDITION(PRECONDITIONS.RUN);
            WAITCONTROL.LinkTO(SENTINELLACONTROL).addPRECONDITION(PRECONDITIONS.WALK,ACTIONS.START);
            WAITCONTROL.LinkTO(ONEPASS).addPRECONDITION(PRECONDITIONS.ONEPASS);
            WAITCONTROL.LinkTO(SUICIDE).addPRECONDITION(PRECONDITIONS.ZERO);
            WAITCONTROL.LinkTO(SHOOTCONTROL).addPRECONDITION(PRECONDITIONS.ZETA, ACTIONS.SHOOTSTART);
            
            SHOOTCONTROL.LinkTO(WAITCONTROL).addPRECONDITION(PRECONDITIONS.ZETAUP,ACTIONS.SHOOTSTOP);
            SHOOTCONTROL.LinkTO(SHOOTCONTROL).addPRECONDITION(PRECONDITIONS.KILLER);

            SUICIDE.LinkTO(WAITCONTROL).addPRECONDITION(PRECONDITIONS.ZEROUP);
            SUICIDE.LinkTO(DEAD).addPRECONDITION(PRECONDITIONS.ENDSTATE,ACTIONS.SPLAT);

            ONEPASS.LinkTO(WAITCONTROL).addPRECONDITION(PRECONDITIONS.BLOCK);
            ONEPASS.LinkTO(WAITCONTROL).addPRECONDITION(PRECONDITIONS.WALKSTOP);

            SENTINELLACONTROL.LinkTO(WAITCONTROL).addPRECONDITION(PRECONDITIONS.BLOCK);
            SENTINELLACONTROL.LinkTO(WAITCONTROL).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.ENDSTATE,PRECONDITIONS.WALKSTOP),ACTIONS.STOP);
            SENTINELLACONTROL.LinkTO(SENTINELLACONTROL).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.ENDSTATE, PRECONDITIONS.WALK), ACTIONS.PASS3);
            
            RUNNERCONTROL.LinkTO(RUNSTOPCONTROL).addPRECONDITION(PRECONDITIONS.WALKSTOP);
            RUNNERCONTROL.LinkTO(WAITCONTROL).addPRECONDITION(PRECONDITIONS.BLOCK,ACTIONS.OUCH);

            RUNSTOPCONTROL.LinkTO(WAITCONTROL).addPRECONDITION(PRECONDITIONS.ENDSTATE);
            RUNSTOPCONTROL.LinkTO(WAITCONTROL).addPRECONDITION(PRECONDITIONS.BLOCK, ACTIONS.OUCH);
            
            if(state == "SLEEP")
                CURRENT_STATE = SLEEP;
            if (state == "SENTINELLA")
                CURRENT_STATE = WAIT;
            if(state == "WAIT")
                CURRENT_STATE = WAIT;
            PREV_STATE = CURRENT_STATE;          
        }

        //Esegue l'automa definito nel costruttore di SLigAI
        //Viene chiamato nel metodo Update della classe Game1
        //[pp.48,49]
        public void ROUTINE()
        {
            if (CURRENT_STATE.name != "DEAD")
            {
                #region ColorMask
                colTypes = game.CurrentLevel.collision(Slig);
                if (colTypes.Contains(COLLISIONS.GRAYAREA))
                {
                    Slig.color = Color.DarkGray;
                }
                if (colTypes.Contains(COLLISIONS.BLACKAREA))
                {
                    Slig.color = Color.DarkGray;
                }
                if (!colTypes.Contains(COLLISIONS.GRAYAREA) & !colTypes.Contains(COLLISIONS.BLACKAREA))
                {
                    Slig.color = Color.White;
                } 
                #endregion

                //La transizione da questi stati può avvenire in qualsiasi momento
                if (CURRENT_STATE == WAIT || CURRENT_STATE == SLEEP || CURRENT_STATE == WAITCONTROL || CURRENT_STATE == JUSTPOSSESSED)
                #region HandleStateTransition
                {
                    if (FINISHEDTransition & precond == null)
                    {
                        precond = CURRENT_STATE.TryChangeState();
                        FINISHEDExecution = CURRENT_STATE.Execute();
                        if (FINISHEDExecution)
                        {
                            CURRENT_STATE.AnimsTODO[CURRENT_STATE.CURRENT_ANIM].Reset();
                            PREV_STATE = CURRENT_STATE;
                        }
                    }
                    if (precond != null)
                    {
                        if (precond.ACTION != null)
                        {
                            FINISHEDTransition = precond.ACTION.DO();
                        }

                        if (FINISHEDTransition)
                        {
                            game.OnerightDownSlig = false;
                            game.OneleftDownSlig = false;
                            CURRENT_STATE = precond.ARC.TO;
                            CURRENT_STATE.ENDSTATE = false;
                            precond = null;
                        }
                    }
                } 
                #endregion

                else//Tutti gli altri stati esigono che tutte le animazione contenute siano state eseguite 
                {
                    //L'arco è stato percorso, esegue lo stato corrente
                    if (FINISHEDTransition)
                    {
                        if (FINISHEDExecution)
                            precond = CURRENT_STATE.TryChangeState();
                        if (precond != null)
                            FINISHEDExecution = true;
                        else
                            FINISHEDExecution = CURRENT_STATE.Execute();
                    }
                    //Tutte le animazione sono state seguite
                    if (FINISHEDExecution)
                    {
                        CURRENT_STATE.AnimsTODO[CURRENT_STATE.CURRENT_ANIM].Reset();
                        PREV_STATE = CURRENT_STATE;
                        if (FINISHEDTransition & precond == null)
                            precond = CURRENT_STATE.TryChangeState();//Controllo precondizioni

                        if (precond != null)//Almeno una precondizione è stata verificata
                        {
                            if (precond.ACTION != null)//Se una precondizione ha associata un'azione
                                FINISHEDTransition = precond.ACTION.DO();//L'azione viene eseguita
                            if (FINISHEDTransition)
                            {
                                CURRENT_STATE = precond.ARC.TO;//L'automa transita nello stato successivo
                                CURRENT_STATE.ENDSTATE = false;
                                precond = null;
                            }
                        }
                    }
                }
            }
            else
            {
                //Gestione morte personaggio
                if (game.abeCONTROL.sligToControl == Slig)
                {
                    game.abeCONTROL.sligToControl = null;
                    game.abeCONTROL.CURRENT_STATE = game.abeCONTROL.WAIT;
                    game.CurrentLevel.Sligs.Remove(Slig);
                    game.CurrentLevel = game.Abe.CurrentLevel;
                    game.ResetVideos(Slig, game.Abe.CurrentLevel);
                }
                Slig.CurrentLevel.Sligs.Remove(Slig);
                game.CurrentLevel.Sligs.Remove(Slig);
                /////////////////////////////////////
            }             
        }
    }

    //Definisce gli stati dell'automa
    //Ogni stato contiene una o più animazioni da eseguire
    //[p.45]
    public class STATE
    {
        public bool ENDSTATE;
        public List<ARC> ARCS; 
        public List<Animation> AnimsTODO;
        
        public int CURRENT_ANIM = 0;
        public string name;
        public SligAI AI;
        public STATE(string name, SligAI AI) 
        {
            ENDSTATE = false;
            this.AI = AI;
            this.name = name;
            AnimsTODO = new List<Animation>();           
            ARCS = new List<ARC>();

            if (name == "WAIT")
            {
                AnimsTODO.Add(AI.Slig.WAIT);              
            }
            if (name == "JUSTPOSSESSED")
            {
                AnimsTODO.Add(AI.Slig.JUSTPOSSESSED);
            }
            if (name == "WAITCONTROL")
            {
                AnimsTODO.Add(AI.Slig.WAIT);
            }
            if (name == "SHOOTCONTROL")
            {
                AnimsTODO.Add(AI.Slig.SHOOT);
                AnimsTODO.Add(AI.Slig.SHOOT);
            }
            if (name == "SENTINELLA")
            {
                AnimsTODO.Add(AI.Slig.PASS1);
                AnimsTODO.Add(AI.Slig.PASS2);
                AnimsTODO.Add(AI.Slig.PASS3);
            }
            if (name == "GOBACKHOME")
            {
                AnimsTODO.Add(AI.Slig.PASS1);
                AnimsTODO.Add(AI.Slig.PASS2);
                AnimsTODO.Add(AI.Slig.PASS3);
            }
            if (name == "GOBACKHOME2")
            {
                AnimsTODO.Add(AI.Slig.PASS1);
                AnimsTODO.Add(AI.Slig.PASS2);
                AnimsTODO.Add(AI.Slig.PASS3);
            }
            if (name == "SENTINELLACONTROL")
            {
                AnimsTODO.Add(AI.Slig.PASS1);
                AnimsTODO.Add(AI.Slig.PASS2);
            }
            if (name == "VEDETTA")
            {
                AnimsTODO.Add(AI.Slig.WAIT);
                AnimsTODO.Add(AI.Slig.TURN);
                AnimsTODO.Add(AI.Slig.WAIT);
                AnimsTODO.Add(AI.Slig.TURN);
                AnimsTODO.Add(AI.Slig.WAIT);
                AnimsTODO.Add(AI.Slig.TURN);

            }
            if (name == "VEDETTA2")
            {
                AnimsTODO.Add(AI.Slig.WAIT);
                AnimsTODO.Add(AI.Slig.TURN);
                AnimsTODO.Add(AI.Slig.WAIT);
                AnimsTODO.Add(AI.Slig.TURN);
                AnimsTODO.Add(AI.Slig.WAIT);
                AnimsTODO.Add(AI.Slig.TURN);

            }
            if (name == "SHOOT")
            {
                AnimsTODO.Add(AI.Slig.SHOOT);
                AnimsTODO.Add(AI.Slig.SHOOT);
            }
            if (name == "SHOOTED")
            {
                AnimsTODO.Add(AI.Slig.POSSESSED);
            }
            if (name == "RUNNER")
            {
                AnimsTODO.Add(AI.Slig.RUN1);
                AnimsTODO.Add(AI.Slig.RUN2);
                AnimsTODO.Add(AI.Slig.RUN3);
                AnimsTODO.Add(AI.Slig.RUN4);
            }
            if (name == "RUNNERCONTROL")
            {
                AnimsTODO.Add(AI.Slig.RUN1);
                AnimsTODO.Add(AI.Slig.RUN2);
                AnimsTODO.Add(AI.Slig.RUN3);
                AnimsTODO.Add(AI.Slig.RUN4);
            }
            if (name == "RUNSTOP")
            {
                AnimsTODO.Add(AI.Slig.RUNsTOP1);
                AnimsTODO.Add(AI.Slig.RUNsTOP2);
            }
            if (name == "RUNSTOPCONTROL")
            {
                AnimsTODO.Add(AI.Slig.RUNsTOP1);
                AnimsTODO.Add(AI.Slig.RUNsTOP2);
            }
            if (name == "SLEEP")
            {
                AnimsTODO.Add(AI.Slig.SLEEP);
            }
            if (name == "POSSESSED")
            {
                AnimsTODO.Add(AI.Slig.POSSESSED);
            }
            if (name == "SUICIDE")
            {
                AnimsTODO.Add(AI.Slig.SUICIDE);
                AnimsTODO.Add(AI.Slig.SUICIDE);
                AnimsTODO.Add(AI.Slig.SUICIDE);
                AnimsTODO.Add(AI.Slig.SUICIDE);
            }
            if (name == "ONEPASS")
            {
                AnimsTODO.Add(AI.Slig.ONEPASS);
                AnimsTODO.Add(AI.Slig.WAIT);
            }
            if (name == "CRAZY1")
            {
                AnimsTODO.Add(AI.Slig.RUN1);
                AnimsTODO.Add(AI.Slig.RUN2);
                AnimsTODO.Add(AI.Slig.RUN3);
                AnimsTODO.Add(AI.Slig.RUN4);
            }
            if (name == "CRAZY2")
            {
                AnimsTODO.Add(AI.Slig.HEELP);
                AnimsTODO.Add(AI.Slig.RUNsTOP2);
            }
            if (name == "DEAD")
            {

            }          
        }
        #region STATEDEFAULT
        public STATE STATEDEFAULT(string state)
        {
            if (state == "WAIT")
                return AI.WAIT;
            if (state == "SENTINELLA")
                return AI.WAIT;
            if (state == "SLEEP")
                return AI.SLEEP;

            return AI.SLEEP;
        } 
        #endregion

        //Riporta uno Slig allo stato iniziale
        public void RESET()
        {
            Slig slig2 = new Slig(AI.game, AI.Slig.state,AI.Slig.AI_LEVEL, AI.Slig.position);
            slig2.levelDefault = AI.Slig.levelDefault;
            AI.Slig.levelDefault.RemoveSlig(AI.Slig);
            AI.Slig.levelDefault.AddSlig(slig2);
            AI.game.Abe.SLIGS.Remove(AI.Slig);
        }

        //Collega due stati e restituisce l'arco associato
        public ARC LinkTO(STATE to)
        {
            ARC arc = new ARC(this.name + "to" + to.name, this, to);

            foreach (ARC arcNew in ARCS)
            {
                if (arcNew.NAME == arc.NAME)
                    return arcNew;
            }          
            this.ARCS.Add(arc);
            return arc;
        }

        //Esegue tutte le animazioni contenute nello stato corrente
        public bool Execute()
        {
            if (!AnimsTODO[CURRENT_ANIM].LastFrameDone)
            {
                AI.Slig.AnimateSLIG(AnimsTODO[CURRENT_ANIM]);
                return false;
            }
            else
            {
                if (CURRENT_ANIM == AnimsTODO.Count - 1)
                {
                    ENDSTATE = true;
                    CURRENT_ANIM = 0;
                }
                else
                {
                    CURRENT_ANIM++;
                    AnimsTODO[CURRENT_ANIM].Reset();
                }
                return true;
            }
        }

        //Controlla le precondizioni di tutti gli archi uscenti
        public PRECONDITION TryChangeState()
        {
            foreach (ARC arc in AI.CURRENT_STATE.ARCS)
            {
                foreach (PRECONDITION precondition in arc.PRECONDITIONS)
                {
                    if (precondition.Verify())
                    {
                        CURRENT_ANIM = 0;
                        return precondition;
                    }
                }
            }
            return null;
        }
    }

    //Definisce gli archi dell'automa
    //[p.47]
    public class ARC
    {
        string name;
        STATE from;
        STATE to;
        
        List<PRECONDITION> preconditions;

        
        public ARC(string name, STATE from, STATE to)
        {
            preconditions = new List<PRECONDITION>();
            this.name = name;
            this.from = from;
            this.to = to;
        }

        //Pone una precondizione sull'arco
        public void addPRECONDITION(PRECONDITION precondition)
        {
            PRECONDITION p = new PRECONDITION(from.AI, precondition.NAME);
            p.prec1 = precondition.prec1;
            p.prec2 = precondition.prec2;
            preconditions.Add(p);
            p.ARC = this;
        }

        //Pone una precondizione e un'azione sull'arco
        //Se la precondizione è verificata, viene eseguita l'azione
        public void addPRECONDITION(PRECONDITION precondition, ACTION action)
        {
            PRECONDITION p = new PRECONDITION(from.AI, precondition.NAME);
            p.prec1 = precondition.prec1;
            p.prec2 = precondition.prec2;
            preconditions.Add(p);
            p.addACTION(action);
            p.ARC = this;
        }

        #region Attribute
        public string NAME
        {
            get { return name; }
        }

        public List<PRECONDITION> PRECONDITIONS
        {
            get { return preconditions; }
        }

        public STATE FROM
        {
            get { return from; }
        }

        public STATE TO
        {
            get { return to; }
        }
        #endregion

    }


    //Definisce le precondizioni che devono essere aggiunte ad un arco per transitare da uno stato all'altro.
    //[p.46]
    public class PRECONDITION
    {
        string name;
        SligAI AI;
        ACTION action;
        ARC arc;
        public PRECONDITION prec1;
        public PRECONDITION prec2;
        public PRECONDITION(SligAI AI, string name) 
        {
            this.name = name;
            this.AI = AI;         
        }

        public void addACTION(ACTION action)
        {
            this.action = action;
        }

        //Controlla se la precondizione è soddisfatta
        public bool Verify()
        {
            if (name == "WALK")
            {
                if (((AI.game.rightDownSlig & AI.Slig.Direction == 1) || (AI.game.leftDownSlig & AI.Slig.Direction == -1)) & !AI.game.shiftDown)
                    return true;
            }
            if (name == "ONEPASS")
            {
                if (((AI.game.OnerightDownSlig & AI.Slig.Direction == 1) || (AI.game.OneleftDownSlig & AI.Slig.Direction == -1)) & !AI.game.shiftDown)
                {
                    AI.game.OnerightDownSlig = false;
                    AI.game.OneleftDownSlig = false;
                    return true;
                }
            }
            if (name == "WALKSTOP")
            {
                if (((!AI.game.rightDownSlig & AI.Slig.Direction == 1) || (!AI.game.leftDownSlig & AI.Slig.Direction == -1)))
                    return true;
            }
            if (name == "TURN")
            {
                if ((AI.Slig.Direction == -1 & AI.game.rightDown) || (AI.Slig.Direction == 1 & AI.game.leftDown))
                    return true;
            }
            if (name == "RUN")
            {
                if (((AI.game.rightDown & AI.Slig.Direction == 1) || (AI.game.leftDown & AI.Slig.Direction == -1)) & AI.game.shiftDown)
                    return true;
            }
            if (name == "ZERO")
            {
                if (AI.game.ZeroDown)
                {
                    if( AI.CURRENT_STATE.name == "SUICIDE" & AI.CURRENT_STATE.ENDSTATE)
                        AI.Slig.DEAD = true;
                    return true;
                }
            }
            if (name == "ZEROUP")
            {
                if (!AI.game.ZeroDown)
                    return true;
            }
            if (name == "ZETA")
            {
                if (AI.game.zetaDown)
                    return true;
            }
            if (name == "ZETAUP")
            {
                if (!AI.game.zetaDown)
                    return true;
            }
            if (name == "ENDSTATE")
            {
                if (AI.CURRENT_STATE.ENDSTATE)
                {
                    return true;
                }
            }
            if (name == "ENDSCREEN")
            {
                if ((AI.Slig.boundingBox.Right >= 500 & AI.Slig.Direction == 1) || (AI.Slig.boundingBox.X <= 50 & AI.Slig.Direction == -1))//(AI.Slig.boundingBox.X <= 50 & AI.Slig.Direction == -1) || 
                    return true;
            }
            if (name == "BLOCK")
            {
                List<string> ColTypes = AI.Slig.CurrentLevel.collision(AI.Slig);
                if (ColTypes.Contains(COLLISIONS.BLOCCO))
                    return true;
            }
            if (name == "GODOWN")
            {
                List<string> ColTypes = AI.Slig.CurrentLevel.collision(AI.Slig);
                if (ColTypes.Contains(COLLISIONS.GODOWN))
                {
                    AI.Slig.DEAD = true;
                    return true;
                }
            }
            if (name == "GODOWND")
            {
                List<string> ColTypes = AI.Slig.CurrentLevel.collision(AI.Slig);
                if (ColTypes.Contains(COLLISIONS.BOTOLA))// || Godownd
                {
                    AI.Slig.DEAD = true;
                    return true;
                }
            }
            if (name == "MATTATOIO")
            {
                List<string> ColTypes = AI.Slig.CurrentLevel.collision(AI.Slig);
                if (ColTypes.Contains(COLLISIONS.MATTATOIO))
                {
                    AI.Slig.DEAD = true;
                    return true;
                }
            }
            if (name == "ABENOISE")
            {
                if (AI.game.Abe.AbeNoise & AI.Slig.CurrentLevel == AI.game.CurrentLevel)
                {
                    return true;
                }
            }
            if (name == "ABEAHEAD")
            {
                if (AI.Slig.CurrentLevel.NAME == AI.game.Abe.CurrentLevel.NAME)
                {
                    if (((AI.game.Abe.boundingBox.X >= AI.Slig.boundingBox.X & AI.Slig.Direction == 1) || (AI.game.Abe.boundingBox.X < AI.Slig.boundingBox.X & AI.Slig.Direction == -1)) & AI.Slig.CurrentLevel == AI.game.Abe.CurrentLevel)
                    {
                        return true;
                    }
                }
                else
                {
                    if ((AI.Slig.CurrentLevel.NextRIGHT != null && AI.Slig.CurrentLevel.NextRIGHT.NAME == AI.game.Abe.CurrentLevel.NAME && AI.Slig.Direction == 1)
                        ||(AI.Slig.CurrentLevel.NextLEFT != null && AI.Slig.CurrentLevel.NextLEFT.NAME == AI.game.Abe.CurrentLevel.NAME && AI.Slig.Direction == -1))
                        return true;
                }
            }
            if (name == "ABEBEHIND")
            {
                if (AI.Slig.CurrentLevel.NAME == AI.game.Abe.CurrentLevel.NAME)
                {
                    if (((AI.game.Abe.boundingBox.X > AI.Slig.boundingBox.X & AI.Slig.Direction == -1) || (AI.game.Abe.boundingBox.X < AI.Slig.boundingBox.X & AI.Slig.Direction == 1)) & AI.Slig.CurrentLevel == AI.game.Abe.CurrentLevel)
                        return true;
                }
                else
                {
                    if ((AI.Slig.CurrentLevel.NextRIGHT != null && AI.Slig.CurrentLevel.NextRIGHT.NAME == AI.game.Abe.CurrentLevel.NAME && AI.Slig.Direction == -1)
                        || (AI.Slig.CurrentLevel.NextLEFT != null && AI.Slig.CurrentLevel.NextLEFT.NAME == AI.game.Abe.CurrentLevel.NAME && AI.Slig.Direction == 1))
                        return true;
                }
            }
            if (name == "LOOKATMUDOKON")
            {
                if (AI.Slig.SligEye.Intersects(AI.game.Abe.boundingBox) & AI.Slig.CurrentLevel.NAME == AI.game.Abe.CurrentLevel.NAME)
                {
                    AI.ABE_DETECTED = true;

                    if (!AI.game.Abe.SLIGS.Contains(AI.Slig))
                        AI.game.Abe.SLIGS.Add(AI.Slig);
                    return true;
                }
            }
            if (name == "ABEDETECTED")
            {
                if (AI.ABE_DETECTED)
                    return true;
            }
            if (name == "NOTLOOKATABE")
            {
                if (!AI.Slig.SligEye.Intersects(AI.game.Abe.boundingBox) & AI.Slig.CurrentLevel.NAME == AI.game.Abe.CurrentLevel.NAME)
                {
                    return true;
                }
            }
            if (name == "ABEKILLED")
            {
                bool OK = false;
                if (AI.CURRENT_STATE.name == "SHOOT" & AI.CURRENT_STATE.ENDSTATE)
                {
                    if (AI.Slig.SligEye.Intersects(AI.game.Abe.boundingBox))
                    {
                        OK = true;
                        AI.game.Abe.DEAD = true;
                    }
                    foreach (Mudokon MUD in AI.Slig.CurrentLevel.Mudokons)
                    {
                        if (AI.Slig.SligEye.Intersects(MUD.boundingBox))
                        {
                            MUD.AI.CURRENT_STATE = MUD.AI.SHOOTED;
                            MUD.DEAD = true;
                        }

                    }
                    if(OK)
                        return true;
                }
            }
            if (name == "KILLER")
            {
                if (AI.CURRENT_STATE == AI.SHOOTCONTROL & AI.CURRENT_STATE.ENDSTATE)
                {
                    foreach (Mudokon MUD in AI.Slig.CurrentLevel.Mudokons)
                    {
                        if (AI.Slig.SligEye.Intersects(MUD.boundingBox))
                        {
                            MUD.AI.CURRENT_STATE = MUD.AI.SHOOTED;
                            MUD.DEAD = true;
                        }

                    }

                    foreach (Slig slig in AI.Slig.CurrentLevel.Sligs)
                    {
                        if (slig != AI.Slig)
                        {
                            if (AI.Slig.SligEar.Intersects(slig.boundingBox))
                            {
                                slig.AI.CURRENT_STATE = slig.AI.SHOOTED;
                                slig.DEAD = true;
                            }
                        }
                    }
                }
            }
            if (name == "ABESAMELVL")
            {
                if (AI.Slig.CurrentLevel.NAME == AI.game.Abe.CurrentLevel.NAME)
                    return true;
            }
            if (name == "ABENOTSAMELVL")
            {
                if (AI.Slig.CurrentLevel.NAME != AI.game.Abe.CurrentLevel.NAME && AI.game.abeCONTROL.CURRENT_STATE != AI.game.abeCONTROL.NOTCONTROL)
                {
                    AI.ABE_DETECTED = false;
                    if ((AI.CURRENT_STATE == AI.SENTINELLA || AI.CURRENT_STATE == AI.VEDETTA) & AI.Slig.levelDefault.NAME == AI.Slig.CurrentLevel.NAME)
                    {
                        if (AI.game.Abe.SLIGS.Contains(AI.Slig))
                            AI.game.Abe.SLIGS.Remove(AI.Slig);
                    }
                    return true;
                }
            }
            if (name == "LVLCHANGED")
            {
                if (AI.Slig.levelDefault.NAME != AI.Slig.CurrentLevel.NAME)
                {
                    //AI.Slig.levelDefault = AI.Slig.CurrentLevel;
                    if(!AI.ABE_DETECTED)
                        AI.game.Abe.SLIGS.Remove(AI.Slig);
                    return true;
                }
            }
            if (name == "NOTATHOME")
            {
                if (AI.Slig.levelDefault.NAME != AI.Slig.CurrentLevel.NAME)
                    return true;
            }
            if (name == "ATHOME")
            {
                if (AI.Slig.levelDefault.NAME == AI.Slig.CurrentLevel.NAME)
                    return true;
            }
            if (name == "AND")
            {
                return this.prec1.Verify() & this.prec2.Verify();
            }
            if (name == "ABECONTROL")
            {
                if (AI.game.abeCONTROL.CURRENT_STATE.name == "NOTCONTROL")
                {
                    if (AI.game.abeCONTROL.sligToControl == AI.Slig)
                        return true;
                    else
                        AI.CURRENT_STATE = AI.SENTINELLA;
                }
            }
            if (name == "ABEOMM")
            {
                if (AI.game.abeCONTROL.CURRENT_STATE.name == "OMM")
                    return true;
            }
            if (name == "ABENOTOMM")
            {
                if (AI.game.abeCONTROL.CURRENT_STATE.name != "OMM" && AI.game.abeCONTROL.CURRENT_STATE != AI.game.abeCONTROL.NOTCONTROL)
                    return true;
            }
            return false;
        }

        #region Attribute
        public ACTION ACTION
        {
            get { return action; }
        }
        public ARC ARC
        {
            get { return arc; }
            set { arc = value; }
        }
        public string NAME
        {
            get { return name; }
        } 
        #endregion
    }

    //Contiene i riferimenti a tutte le istanze della classe PRECONDITION 
    public class PRECONDITIONS
    {
        SligAI AI;
        public PRECONDITION BLOCK;
        public PRECONDITION ENDSCREEN;
        public PRECONDITION ABEAHEAD;
        public PRECONDITION ABEBEHIND;
        public PRECONDITION ABENOISE;
        public PRECONDITION LOOKATMUDOKON;
        public PRECONDITION NOTLOOKATABE;
        public PRECONDITION ENDSTATE;
        public PRECONDITION ABEKILLED;
        public PRECONDITION GODOWN;
        public PRECONDITION GODOWND;
        public PRECONDITION MATTATOIO;
        public PRECONDITION LVLCHANGED;
        public PRECONDITION NOTATHOME;
        public PRECONDITION ATHOME;
        public PRECONDITION ABESAMELVL;
        public PRECONDITION ABENOTSAMELVL;
        public PRECONDITION ABEDETECTED;
        public PRECONDITION ABECONTROL;
        public PRECONDITION ABEOMM;
        public PRECONDITION ABENOTOMM;

        public PRECONDITION WALK;
        public PRECONDITION ONEPASS;
        public PRECONDITION WALKSTOP;
        public PRECONDITION TURN;
        public PRECONDITION RUN;
        public PRECONDITION ZERO;
        public PRECONDITION ZEROUP;
        public PRECONDITION ZETA;
        public PRECONDITION ZETAUP;
        public PRECONDITION KILLER;


        public PRECONDITIONS(SligAI AI)
        {
            this.AI = AI;
            BLOCK = new PRECONDITION(AI, "BLOCK");
            ENDSCREEN = new PRECONDITION(AI, "ENDSCREEN");
            ABEAHEAD = new PRECONDITION(AI, "ABEAHEAD");
            ABEBEHIND = new PRECONDITION(AI, "ABEBEHIND");
            ABENOISE = new PRECONDITION(AI, "ABENOISE");

            LOOKATMUDOKON = new PRECONDITION(AI, "LOOKATMUDOKON");
            NOTLOOKATABE = new PRECONDITION(AI, "NOTLOOKATABE");
            ENDSTATE = new PRECONDITION(AI, "ENDSTATE");
            ABEKILLED = new PRECONDITION(AI, "ABEKILLED");
            GODOWN = new PRECONDITION(AI, "GODOWN");
            GODOWND = new PRECONDITION(AI, "GODOWND");
            MATTATOIO = new PRECONDITION(AI, "MATTATOIO");
            LVLCHANGED = new PRECONDITION(AI, "LVLCHANGED");
            NOTATHOME = new PRECONDITION(AI, "NOTATHOME");
            ATHOME = new PRECONDITION(AI, "ATHOME");
            ABESAMELVL = new PRECONDITION(AI, "ABESAMELVL");
            ABENOTSAMELVL = new PRECONDITION(AI, "ABENOTSAMELVL");
            ABEDETECTED = new PRECONDITION(AI, "ABEDETECTED");
            ABECONTROL = new PRECONDITION(AI, "ABECONTROL");
            ABEOMM = new PRECONDITION(AI, "ABEOMM");
            ABENOTOMM = new PRECONDITION(AI, "ABENOTOMM");
            WALK = new PRECONDITION(AI, "WALK");
            ONEPASS = new PRECONDITION(AI, "ONEPASS");
            WALKSTOP = new PRECONDITION(AI, "WALKSTOP");
            TURN = new PRECONDITION(AI, "TURN");
            RUN = new PRECONDITION(AI, "RUN");
            ZERO = new PRECONDITION(AI, "ZERO");
            ZEROUP = new PRECONDITION(AI, "ZEROUP");
            ZETA = new PRECONDITION(AI, "ZETA");
            ZETAUP = new PRECONDITION(AI, "ZETAUP");
            KILLER = new PRECONDITION(AI, "KILLER");

        }

        public PRECONDITION AND(PRECONDITION prec1, PRECONDITION prec2)
        {
            PRECONDITION precResult = new PRECONDITION(AI, "AND");
            precResult.prec1 = prec1;
            precResult.prec2 = prec2;

            return precResult;

        }
    }


    //Definisce le azioni che possono essere associate ad una precondizione
    //Ogni azione può contenere una o più precondizioni.
    //[p.45]
    public class ACTION
    {
        SligAI AI;
        string name;
        public List<Animation> AnimsTODO;
        int CURRENT_ANIM = 0;


        public ACTION(SligAI AI, string name)
        {
            AnimsTODO = new List<Animation>();
            this.AI = AI;
            this.name = name;

            if (name == "WAIT")
            {
                AnimsTODO.Add(AI.Slig.WAIT);
            }
            if (name == "SUICIDE")
            {
                AnimsTODO.Add(AI.Slig.POSSESSED);
            }
            if (name == "WHAAT")
            {
                AnimsTODO.Add(AI.Slig.WHAAT);
            }
            if (name == "OUCH")
            {
                AnimsTODO.Add(AI.Slig.OUCH);
            }
            if (name == "FREEZE")
            {
                AnimsTODO.Add(AI.Slig.FREEZE);
            }
            if (name == "STOP")
            {
                AnimsTODO.Add(AI.Slig.PASSsTOP);
            }
            if (name == "PASS3")
            {
                AnimsTODO.Add(AI.Slig.PASS3);
            }
            if (name == "START")
            {
                AnimsTODO.Add(AI.Slig.START);
            }
            if (name == "TURN")
            {
                AnimsTODO.Add(AI.Slig.TURN);
            }

            if (name == "DOWNPLANE")
            {
                AnimsTODO.Add(AI.Slig.DOWNPLANE);
            }

            if (name == "SPLAT")
            {
                AnimsTODO.Add(AI.Slig.SPLAT);
            }
            if (name == "SHOOTSTART")
            {
                AnimsTODO.Add(AI.Slig.SHOOTsTART);
            }
            if (name == "SHOOTSTOP")
            {
                AnimsTODO.Add(AI.Slig.SHOOTsTOP);
            }
            if (name == "RUNSTART")
            {
                AnimsTODO.Add(AI.Slig.RUNsTART);
            }
            if (name == "RUNSTOP")
            {
                AnimsTODO.Add(AI.Slig.RUNsTOP1);
                AnimsTODO.Add(AI.Slig.RUNsTOP2);
            }
            if (name == "WAKE")
            {
                AnimsTODO.Add(AI.Slig.WAKE);
            }
            if (name == "KILLABE")
            {
                AnimsTODO.Add(AI.Slig.SHOOT);
                AnimsTODO.Add(AI.Slig.SHOOTsTOP);
                AnimsTODO.Add(AI.Slig.START);
            }
        }

        #region Repeat
        public ACTION REPEAT(int repeat)
        {
            ACTION ac = new ACTION(AI, "REPEAT");

            for (int i = 0; i < repeat; i++)
            {
                foreach (Animation anim in this.AnimsTODO)
                    ac.AnimsTODO.Add(anim);
            }

            return ac;
        }
        #endregion

        //Metodo chiamato per eseguire tutte le animazioni contenute in un'azione
        public bool DO()
        {
            if (!AnimsTODO[CURRENT_ANIM].LastFrameDone)
            {
                AI.Slig.AnimateSLIG(AnimsTODO[CURRENT_ANIM]);
                return false;
            }
            else
            {
                if (CURRENT_ANIM == AnimsTODO.Count - 1)
                {
                    CURRENT_ANIM = 0;
                    AI.CURRENT_STATE.CURRENT_ANIM = 0;
                    return true;
                }
                else
                {                  
                    CURRENT_ANIM++;
                    AnimsTODO[CURRENT_ANIM].Reset();
                }
                return false;

            }
        }

        #region Attribute
        public string NAME
        {
            get { return name; }
        }
        #endregion
    }

    //Contiene i riferimenti a tutte le istanze della classe ACTION 
    public class ACTIONS
    {
        SligAI AI;
        public ACTION STOP;
        public ACTION START;
        public ACTION TURN;
        public ACTION SHOOTSTART;
        public ACTION SHOOTSTOP;
        public ACTION RUNSTART;
        public ACTION RUNSTOP;
        public ACTION WAKE;
        public ACTION KILLABE;
        public ACTION WAIT;
        public ACTION WHAAT;
        public ACTION FREEZE;
        public ACTION DOWNPLANE;
        public ACTION SPLAT;
        public ACTION PASS3;
        public ACTION OUCH;
        public ACTION SUICIDE;

        public ACTIONS(SligAI AI)
        {
            this.AI = AI;
            STOP = new ACTION(AI, "STOP");
            START = new ACTION(AI, "START");
            TURN = new ACTION(AI, "TURN");

            SHOOTSTART = new ACTION(AI, "SHOOTSTART");
            SHOOTSTOP = new ACTION(AI, "SHOOTSTOP");
            RUNSTART = new ACTION(AI, "RUNSTART");
            RUNSTOP = new ACTION(AI, "RUNSTOP");
            WAKE = new ACTION(AI, "WAKE");
            KILLABE = new ACTION(AI, "KILLABE");
            WAIT = new ACTION(AI, "WAIT");
            WHAAT = new ACTION(AI, "WHAAT");
            FREEZE = new ACTION(AI, "FREEZE");
            DOWNPLANE = new ACTION(AI, "DOWNPLANE");
            SPLAT = new ACTION(AI, "SPLAT");
            PASS3 = new ACTION(AI, "PASS3");
            OUCH = new ACTION(AI, "OUCH");
            SUICIDE = new ACTION(AI, "SUICIDE");

        }

        public ACTION AND(ACTION action1, ACTION action2)
        {
            ACTION action = new ACTION(AI, "AND");

            foreach (Animation anim in action1.AnimsTODO)
                action.AnimsTODO.Add(anim);
            foreach (Animation anim in action2.AnimsTODO)
                action.AnimsTODO.Add(anim);

            return action;
        }
    }


}
